// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ****************************************************************************
//  File: ParallelCoordinatesViewerEnginePluginInfo.C
// ****************************************************************************

#include <ParallelCoordinatesPluginInfo.h>
#include <avtParallelCoordinatesPlot.h>
#include <ParallelCoordinatesAttributes.h>

//
// Storage for static data elements.
//
ParallelCoordinatesAttributes *ParallelCoordinatesViewerEnginePluginInfo::clientAtts = NULL;
ParallelCoordinatesAttributes *ParallelCoordinatesViewerEnginePluginInfo::defaultAtts = NULL;

// ****************************************************************************
//  Method:  ParallelCoordinatesViewerEnginePluginInfo::InitializeGlobalObjects
//
//  Purpose:
//    Initialize the plot atts.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************
void
ParallelCoordinatesViewerEnginePluginInfo::InitializeGlobalObjects()
{
    if (ParallelCoordinatesViewerEnginePluginInfo::clientAtts == NULL)
    {
        ParallelCoordinatesViewerEnginePluginInfo::clientAtts  = new ParallelCoordinatesAttributes;
        ParallelCoordinatesViewerEnginePluginInfo::defaultAtts = new ParallelCoordinatesAttributes;
    }
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Return a pointer to the viewer client attributes.
//
//  Returns:    A pointer to the viewer client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
ParallelCoordinatesViewerEnginePluginInfo::GetClientAtts()
{
    return clientAtts;
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::GetDefaultAtts
//
//  Purpose:
//    Return a pointer to the viewer default attributes.
//
//  Returns:    A pointer to the viewer default attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
ParallelCoordinatesViewerEnginePluginInfo::GetDefaultAtts()
{
    return defaultAtts;
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::SetClientAtts
//
//  Purpose:
//    Set the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to the new client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
ParallelCoordinatesViewerEnginePluginInfo::SetClientAtts(AttributeSubject *atts)
{
    *clientAtts = *(ParallelCoordinatesAttributes *)atts;
    clientAtts->Notify();
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Get the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to return the client default attributes in.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
ParallelCoordinatesViewerEnginePluginInfo::GetClientAtts(AttributeSubject *atts)
{
    *(ParallelCoordinatesAttributes *)atts = *clientAtts;
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::AllocAvtPlot
//
//  Purpose:
//    Return a pointer to a newly allocated avt plot.
//
//  Returns:    A pointer to the newly allocated avt plot.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

avtPlot *
ParallelCoordinatesViewerEnginePluginInfo::AllocAvtPlot()
{
    return new avtParallelCoordinatesPlot;
}

bool
ParallelCoordinatesViewerEnginePluginInfo::Permits2DViewScaling() const
{
    return false;
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::InitializePlotAtts
//
//  Purpose:
//    Initialize the plot attributes to the default attributes.
//
//  Arguments:
//    atts      The attribute subject to initialize.
//    md        The metadata used to initialize.
//    atts      The variable name used to initialize.
//
//  Programmer: Jeremy Meredith
//  Creation:   February  6, 2008
//
//  Modifications:
//    Jeremy Meredith, Thu Feb  7 17:49:50 EST 2008
//    Took out all the parsing.  It was never a good idea.
//
//    Jeremy Meredith, Mon Feb 18 14:51:40 EST 2008
//    Added a little smarts to attempt to populate the axis names.
//    Note that this did require adding some minimal parsing in -- however,
//    we are not relying on it; if it fails, everything still works, except
//    that the GUI window can't tell the user what the axis names are until
//    the axis restriction tool has been used to limit the axis extents.
//
// ****************************************************************************
#include <avtPlotMetaData.h>
#include <ParsingExprList.h>
#include <Expression.h>
#include <ColorAttribute.h>
#include <ExprNode.h>
#include <avtArrayMetaData.h>
#include <avtDatabaseMetaData.h>

#include <InvalidVariableException.h>
#include <ImproperUseException.h>
#include <DebugStream.h>

void
ParallelCoordinatesViewerEnginePluginInfo::InitializePlotAtts(
    AttributeSubject *atts, const avtPlotMetaData &plot)
{
    // If we had scalar names, we can just copy the default atts
    // and return.
    if (defaultAtts->GetScalarAxisNames().size() != 0)
    {
        // One helpful thing we can do: make sure the user set the
        // visual axis names.  They really should have, but since
        // we can blindly copy them from the scalar axis names in
        // this case, no harm doing it for them.
        if (defaultAtts->GetVisualAxisNames().size() == 0)
            defaultAtts->SetVisualAxisNames(defaultAtts->GetScalarAxisNames());

        *(ParallelCoordinatesAttributes*)atts = *defaultAtts;

        return;
    }

    // Otherwise,  we must be an array variable; try to get
    // some names for its components....
    const avtDatabaseMetaData *md = plot.GetMetaData();
    const std::string &var = plot.GetVariableName();
    const avtArrayMetaData *array = md->GetArray(var);
    stringVector subNames;
    if (array)
    {
        subNames = array->compNames;
    }
    else
    {
        Expression const *exp =
            ParsingExprList::GetExpression(plot.GetVariableName());
        if (exp == NULL || exp->GetType() != Expression::ArrayMeshVar)
        {
            debug3 << "ParallelCoordinatesAttributes::InitializePlotAtts: "
                   << "variable wasn't an array database variable, an "
                   << "array expression, or a list of scalars.  This can "
                   << "happen if the user attempts to create this plot "
                   << "without the use off a wizard, e.g. in the case of "
                   << "the cli.  Assuming this is the case and continuing "
                   << "without error.\n";
            return;
        }
        // If we have any problems walking the expression tree, just return;
        // the worst case scenario if we don't populate the visual axis
        // name list is that the GUI window is temporarily blank.
        ExprNode *root = ParsingExprList::GetExpressionTree(exp);
        if (root->GetTypeName() != "Function")
            return;
        FunctionExpr *fn = dynamic_cast<FunctionExpr*>(root);
        if (fn->GetName() != "array_compose" &&
            fn->GetName() != "array_compose_with_bins")
            return;
        ArgsExpr *argsExpr = fn->GetArgsExpr();
        std::vector<ArgExpr*> *args = argsExpr ? argsExpr->GetArgs() : NULL;
        if (!args)
            return;
        for (size_t i=0; i<args->size(); i++)
        {
            ExprNode *arg = (ExprNode*)((*args)[i]->GetExpr());
            if (arg->GetTypeName() == "List")
                break;
            subNames.push_back(arg->GetPos().GetText(exp->GetDefinition()));
        }
    }

    doubleVector extMin(subNames.size(), -1e+37);
    doubleVector extMax(subNames.size(), +1e+37);

    // Set up the default attributes to contain these values, so
    // if the user hits reset, the axis names are retained.
    defaultAtts->SetVisualAxisNames(subNames);
    defaultAtts->SetExtentMinima(extMin);
    defaultAtts->SetExtentMaxima(extMax);
    *(ParallelCoordinatesAttributes*)atts = *defaultAtts;
}

// ****************************************************************************
//  Method: ParallelCoordinatesViewerEnginePluginInfo::GetMenuName
//
//  Purpose:
//    Return a pointer to the name to use in the viewer menus.
//
//  Returns:    A pointer to the name to use in the viewer menus.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

const char *
ParallelCoordinatesViewerEnginePluginInfo::GetMenuName() const
{
    return "Parallel Coordinates";
}

